#!/usr/bin/env python3
"""
使用pymodbus 3.9版本的多从站Modbus RTU模拟器示例
"""

import logging
import time
import sys
import threading
from pymodbus.server import StartSerialServer
from pymodbus.device import ModbusDeviceIdentification
from pymodbus.datastore import ModbusSequentialDataBlock
from pymodbus.datastore import ModbusSlaveContext, ModbusServerContext
from pymodbus.framer import FramerType

# 配置日志
logging.basicConfig()
log = logging.getLogger()
log.setLevel(logging.DEBUG)

def setup_slave_context(slave_id, initial_values=None):
    """为特定从站创建数据存储区"""
    if initial_values is None:
        initial_values = {
            'hr': [0] * 100,  # 保持寄存器
            'ir': [0] * 100,  # 输入寄存器
            'co': [0] * 100,  # 线圈
            'di': [0] * 100   # 离散输入
        }
    
    store = ModbusSlaveContext(
        di=ModbusSequentialDataBlock(0, initial_values['di']),
        co=ModbusSequentialDataBlock(0, initial_values['co']),
        hr=ModbusSequentialDataBlock(0, initial_values['hr']),
        ir=ModbusSequentialDataBlock(0, initial_values['ir']),
        # slave=slave_id
    )
    
    return store

def run_updating_server(context):
    """后台线程用于更新模拟数据"""
    slave_1 = 0x01
    slave_2 = 0x02
    
    counter = 0
    while True:
        counter += 1
        # 更新从站1的数据
        context[slave_1].setValues(3, 0, [counter, counter + 1, counter + 2])  # 保持寄存器
        context[slave_1].setValues(4, 0, [counter * 10, counter * 10 + 1])    # 输入寄存器
        context[slave_1].setValues(1, 0, [counter % 2 == 0, counter % 3 == 0])  # 线圈
        context[slave_1].setValues(2, 0, [counter % 2 == 1, counter % 3 == 1])  # 离散输入
        
        # 更新从站2的数据
        context[slave_2].setValues(3, 0, [counter * 2, counter * 2 + 1])      # 保持寄存器
        context[slave_2].setValues(4, 0, [counter * 20, counter * 20 + 1])    # 输入寄存器
        context[slave_2].setValues(1, 0, [counter % 3 == 0, counter % 4 == 0])  # 线圈
        context[slave_2].setValues(2, 0, [counter % 3 == 1, counter % 4 == 1])  # 离散输入
        
        time.sleep(1)  # 每秒更新一次

def run_server():
    """运行Modbus RTU服务器"""
    # 创建从站上下文
    slave_1_context = setup_slave_context(0x01)
    slave_2_context = setup_slave_context(0x02)
    
    # 创建多从站的服务器上下文
    slaves = {
        0x01: slave_1_context,
        0x02: slave_2_context
    }
    context = ModbusServerContext(slaves=slaves, single=False)
    
    # 创建设备标识
    identity = ModbusDeviceIdentification()
    identity.VendorName = 'Pymodbus'
    identity.ProductCode = 'PM'
    identity.VendorUrl = 'https://github.com/pymodbus-dev/pymodbus'
    identity.ProductName = 'Pymodbus Server'
    identity.ModelName = 'Pymodbus RTU Server'
    identity.MajorMinorRevision = '3.9.0'
    
    # 启动后台线程更新数据
    updater = threading.Thread(target=run_updating_server, args=(context,))
    updater.daemon = True
    updater.start()
    
    # 启动服务器
    print("启动Modbus RTU服务器...")
    # 修改端口和其他参数以匹配您的环境
    # 在Windows上，端口可能是'COM1'，在Linux上可能是'/dev/ttyUSB0'
    # port = '/dev/ttyUSB0'  # 根据您的系统更改
    port = 'COM1'  # 根据您的系统更改
    try:
        StartSerialServer(
            context=context,
            framer=FramerType.RTU,
            identity=identity,
            port=port,
            baudrate=9600,
            bytesize=8,
            parity='N',
            stopbits=1,
            timeout=1,
            unit=1  # 这就是从站ID
        )
    except Exception as e:
        print(f"无法启动服务器: {e}")
        sys.exit(1)

if __name__ == '__main__':
    run_server()